#include "partialseacondition.h"
#include <stdlib.h>
#include <time.h>
#include "freefuncs.h"
#include <assert.h>

PartialSEACondition::PartialSEACondition(int radius, int validHistorySteps): nBIndex(-1), historyStep(-1), condition(is), nBValue(-1)//, nbRadius(radius)
{
	nbRadius = radius;
	this->validHistorySteps = validHistorySteps;
}

bool PartialSEACondition::applies (const PixelHistory&  pixel) const
{
	assert (pixel.age() > this->historyStep);
	switch (condition)
	{
	case is:
		return (pixel.getNBAtTime(nBIndex, historyStep) == nBValue);
	case isnot:
		return (pixel.getNBAtTime(nBIndex, historyStep) != nBValue);
	default:
		cerr << "The condition " << condition << " is not implemented yet. - this will make resaults faulty." << endl;
		return false;
	}
}

void PartialSEACondition::mutateNBIndex (void)
{
	//int maxNBIndex = intPosPow((2*nbRadius+1),2);
	//nBIndex = rand() % maxNBIndex;
	//picking a random number such as above might lead to no change at all (the same value randomly gets generated again).
	//instead, we add an offset between 1 and maximum value-1, add it to the value assuming it goes back to 0 if overflowed (it goes round)
	int maxNBIndexOffset = intPosPow((2*nbRadius+1),2) - 1;
	int nBIndexOffset = (rand() % maxNBIndexOffset) + 1; //this number will be between 1 and maxNBIndex - 1
	nBIndex += nBIndexOffset;
	nBIndex %= maxNBIndexOffset + 2;
}

void PartialSEACondition::mutatehistoryStep (void)
{
	//historyStep = rand() % validHistorySteps;
	int maxHistoryStepOffset = validHistorySteps - 1;
	int historyStepOffset = rand() % maxHistoryStepOffset + 1;
	historyStep = (historyStep + historyStepOffset) % maxHistoryStepOffset;	
}

void PartialSEACondition::mutateCondition (void)
{
	int maxConditionOffset = SEAConditionsNum - 1;
	int conditionOffset = rand() % maxConditionOffset + 1;
	condition = (SEACondition) (((int)condition + conditionOffset ) % (int) SEAConditionsNum);
	//condition = (SEACondition) (rand() % (int) SEAConditionsNum);
}

void PartialSEACondition::mutatenBValue (void)
{
	int maxnBValueOffset = CELLSTATES - 1;
	int nBValueOffset = rand() % maxnBValueOffset + 1;
	nBValue = rand() % CELLSTATES;
}

void PartialSEACondition::randomize (void)
{
	int maxNBIndex = intPosPow((2*nbRadius+1),2);
	nBIndex = rand() % maxNBIndex;
	historyStep = rand() % validHistorySteps;
	condition = (SEACondition) (rand() % (int) SEAConditionsNum);
	nBValue = rand() % CELLSTATES;
}

ostream& operator<< (ostream& stream, const PartialSEACondition& searule)
{
	stream << "neighbor " << searule.nBIndex << " in the history " << searule.historyStep << " ";
	switch (searule.condition)
	{
	case is: 
		stream << "is ";
		break;
	case isnot:
		stream << "is not ";
		break;
	default:
		stream << "__NOT IMPLEMENTED YET ";
	}
	stream << searule.nBValue;
	return stream;
}